import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import logger from 'src/common/utils/log';
import {
  GameStatusEnum,
  MatchStatusEnum,
  TeamEventList,
} from 'src/common/constant/enums';
import { GameInfo } from 'src/modules/game/entities/game.entity';
import { LoginUserResponseDto } from 'src/modules/auth/dto/login-user.dto';
import { MatchService } from 'src/modules/match/match.service';
import { MatchEndService } from './match-end.service';
import { MatchInfo } from 'src/modules/match/entities/match.entity';

type giveUpOptions = {
  operator: LoginUserResponseDto;
};
@Injectable()
export class MatchGiveUpService {
  constructor(
    private readonly matchService: MatchService,
    private readonly matchEndService: MatchEndService,
  ) {}

  async playerGiveUp(
    matchId: string,
    playerId: string,
    type: 'team' | 'player',
    options: giveUpOptions,
  ) {
    let newMathData;
    if (!type || type === 'player') {
      newMathData = await this.getGiveUpData(
        parseInt(matchId),
        parseInt(playerId),
        options,
      );
    } else if (type === 'team') {
      newMathData = await this.getGiveUpData(
        parseInt(matchId),
        parseInt(playerId),
        options,
      );
    }
    await this.matchService.save(newMathData);
    await this.matchEndService.endMatch(newMathData);
  }
  async getGiveUpData(
    matchId: number,
    playerId: number,
    options: giveUpOptions,
  ) {
    logger.info(
      `start playerGiveUp params matchId ${matchId}, playerId ${playerId}`,
    );
    const matchDetail = await this.matchService.getMatchDetail(matchId);
    if (!matchDetail) {
      throw new HttpException(
        `比赛 ${matchId} 不存在`,
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const isHomePlayer = matchDetail.homePlayer.id === playerId;
    const winnerId = isHomePlayer // 参数给的是弃权的，所以另外一个选手是赢家
      ? matchDetail.awayPlayer.id
      : matchDetail.homePlayer.id;
    if (!TeamEventList.includes(matchDetail.type)) {
      return this.updateMatchData(matchDetail, winnerId, options);
    } else {
      return this.teamGiveUp(matchId, playerId, options);
    }
  }
  async teamGiveUp(matchId: number, playerId: number, options: giveUpOptions) {
    logger.info(
      `start teamGiveUp params matchId ${matchId}, playerId ${playerId}`,
    );
    const teamMatchDetail = await this.matchService.getMatchDetail(matchId);
    if (!teamMatchDetail) {
      throw new HttpException(
        `团队比赛 ${matchId} 不存在`,
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const isHomePlayer = teamMatchDetail.homePlayer.id === playerId;
    const isAwayPlayer = teamMatchDetail.awayPlayer.id === playerId;
    if (!isHomePlayer && !isAwayPlayer) {
      throw new HttpException(
        `${playerId} 在该场团队比赛 ${matchId} 中不存在`,
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const playerInfo = isHomePlayer
      ? teamMatchDetail.homePlayer
      : teamMatchDetail.awayPlayer;
    const isTeamPlayer =
      TeamEventList.includes(teamMatchDetail.type) &&
      !playerInfo.subTeamMatchType;
    if (!isTeamPlayer) {
      throw new HttpException(
        `${playerId} 不是是一个团队id 请调用 playerGiveUp`,
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const winnerId = isHomePlayer // 参数给的是弃权的，所以另外一个选手是赢家
      ? teamMatchDetail.awayPlayer.id
      : teamMatchDetail.homePlayer.id;
    let homeTeamWinTime = 0;
    let awayTeamWinTime = 0;
    teamMatchDetail.subMatchInfos.forEach((subMatch, index) => {
      const subWinnerId = isHomePlayer
        ? subMatch.awayPlayer.id
        : subMatch.homePlayer.id;
      this.updateMatchData(subMatch, subWinnerId, options);
      const isHomePlayerWin = subMatch.winnerId === subMatch.homePlayer.id;
      const isAwayPlayerWin = subMatch.winnerId === subMatch.awayPlayer.id;
      homeTeamWinTime = isHomePlayerWin ? homeTeamWinTime + 1 : homeTeamWinTime;
      awayTeamWinTime = isAwayPlayerWin ? awayTeamWinTime + 1 : awayTeamWinTime;
      logger.info(
        `${teamMatchDetail.homePlayer.id} vs ${teamMatchDetail.awayPlayer.id} 第 ${index} 场  ${homeTeamWinTime}: ${awayTeamWinTime}`,
      );
    });
    delete teamMatchDetail.winner;
    teamMatchDetail.winnerId = winnerId;
    teamMatchDetail.status = MatchStatusEnum.Finished;
    teamMatchDetail.actualEnd = new Date();
    teamMatchDetail.homePlayerRally = homeTeamWinTime;
    teamMatchDetail.awayPlayerRally = awayTeamWinTime;
    return teamMatchDetail;
  }
  updateMatchData(
    matchDetail: MatchInfo,
    playerId: number,
    options: { operator: LoginUserResponseDto },
  ) {
    const { id: matchId, type: eventType } = matchDetail;
    const operatorId = options.operator.id;
    matchDetail.updateBy = operatorId;
    const isHomePlayer = matchDetail.homePlayer.id === playerId;
    const isAwayPlayer = matchDetail.awayPlayer.id === playerId;
    if (!isHomePlayer && !isAwayPlayer) {
      throw new HttpException(
        `${playerId} 在该场比赛 ${matchId} 中不存在`,
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    const playerInfo = isHomePlayer
      ? matchDetail.homePlayer
      : matchDetail.awayPlayer;
    const isTeamPlayer =
      TeamEventList.includes(eventType) && !playerInfo.subTeamMatchType;

    if (isTeamPlayer) {
      throw new HttpException(
        `${playerId} 是一个团队id 请调用 teamGiveUp`,
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
    matchDetail.games = matchDetail.games || [];
    const { gameRule, rallyRule: matchRallyRule, games } = matchDetail;
    const winGameCount = gameRule.minWinGames || gameRule.maxWinGames;
    const winRallyCount =
      matchRallyRule.minWinningRally || matchRallyRule.maxWinningRally;
    let homePlayerWinTime = 0;
    let awayPlayerWinTime = 0;
    for (let i = 0; i < winGameCount; i++) {
      if (!games[i]) {
        // 补充新的game
        const game = new GameInfo();
        game.homePlayerId = matchDetail.homePlayer.id;
        game.awayPlayerId = matchDetail.awayPlayer.id;
        game.winnerId = playerInfo.id;
        game.startTime = new Date();
        game.endTime = new Date();
        game.status = GameStatusEnum.Finished;
        game.createBy = operatorId;
        game.createTime = new Date();
        game.updateBy = operatorId;
        game.updateTime = new Date();
        game.gameIndex = i;
        game.matchId = matchId;
        game.homePlayerRally = isHomePlayer ? winRallyCount : 0;
        game.awayPlayerRally = isAwayPlayer ? winRallyCount : 0;
        homePlayerWinTime = isHomePlayer
          ? homePlayerWinTime + 1
          : homePlayerWinTime;
        awayPlayerWinTime = isAwayPlayer
          ? awayPlayerWinTime + 1
          : awayPlayerWinTime;
        // games.push(game);
      } else {
        if (games[i].status !== GameStatusEnum.Finished) {
          const game = games[i];
          game.winnerId = playerInfo.id;
          game.endTime = new Date();
          game.status = GameStatusEnum.Finished;
          game.homePlayerRally = isHomePlayer ? winRallyCount : 0;
          game.awayPlayerRally = isAwayPlayer ? winRallyCount : 0;
          homePlayerWinTime = isHomePlayer
            ? homePlayerWinTime + 1
            : homePlayerWinTime;
          awayPlayerWinTime = isAwayPlayer
            ? awayPlayerWinTime + 1
            : awayPlayerWinTime;
        } else {
          const game = games[i];
          const isHomePlayerWin = game.homePlayerRally > game.awayPlayerRally;
          const isAwayPlayerWin = game.awayPlayerRally > game.homePlayerRally;
          homePlayerWinTime = isHomePlayerWin
            ? homePlayerWinTime + 1
            : homePlayerWinTime;
          awayPlayerWinTime = isAwayPlayerWin
            ? awayPlayerWinTime + 1
            : awayPlayerWinTime;
          game.winnerId = isHomePlayerWin
            ? game.homePlayerId
            : game.awayPlayerId;
        }
      }
      logger.info(
        `${matchDetail.homePlayer.id} vs ${matchDetail.awayPlayer.id} 第 ${i} 局  ${homePlayerWinTime}: ${awayPlayerWinTime}`,
      );
    }
    matchDetail.homePlayerRally = homePlayerWinTime;
    matchDetail.awayPlayerRally = awayPlayerWinTime;
    const isHomePlayerRallyWin = homePlayerWinTime > awayPlayerWinTime;
    matchDetail.winnerId = isHomePlayerRallyWin
      ? matchDetail.homePlayer.id
      : matchDetail.awayPlayer.id;
    matchDetail.status = MatchStatusEnum.Finished;
    matchDetail.actualEnd = new Date();
    // this.matchService.save(matchDetail);
    delete matchDetail.winner;
    return matchDetail;
  }
}
